#include "GameEngine.h"

using namespace std;

namespace gaim{
          
    bool SDL_Event_Comparator::operator()(const SDL_Event& e1, const SDL_Event& e2) const{
         return e1.type < e2.type;
    }
    
    GameEngine::GameEngine(int fps, int x, int y, int w, int h){
            fps_ = fps;   
            SDL_Init( SDL_INIT_EVERYTHING ); 
            mainScreen_ = SDL_SetVideoMode(w, h, 0, SDL_SWSURFACE);
            
            specialKeys_.insert("space");
            specialKeys_.insert("backspace");
            specialKeys_.insert("enter");
            specialKeys_.insert("escape");
            specialKeys_.insert("alt");
            specialKeys_.insert("alt gr");
            specialKeys_.insert("left shift");
            specialKeys_.insert("left ctrl");
            specialKeys_.insert("right shift");
            specialKeys_.insert("right ctrl");                     
    }  

    

	GameEngine::~GameEngine(){
		for(std::set<Sprite*>::iterator i = sprites_.begin(); i != sprites_.end(); ++i)
			sprites_.erase(i);
		SDL_Quit();
	}
	
	

	void GameEngine::add(Sprite* s){
		sprites_.insert(s);
	}
	
	
	
	void GameEngine::remove(Sprite* s){
        //remove s from set using delete
        //if you remove it using erase, it'll call the destructor, which is good, but our vector is of sprite pointers, which dont have destructors 
        
	}
	
	
	
	//Syntax for event examples: "key up d", "key down space", "quit", "pause"
    void GameEngine::registerEvent(string event, voidFunc function){
         
         SDL_Event e;
         
         if (event.substr(0, 3) == "key"){
            int i;
            if (event.substr(4, 2) == "up"){
                 e.type = SDL_KEYDOWN;
                 i = 7;
            }
            else if (event.substr(4, 4) == "down"){
                 e.type = SDL_KEYUP;
                 i = 9;
            }
            else
                throw invalid_argument("'key' must be followed by either 'up' or 'down'.");
            
            string key = event.substr(i);
            if (event.size() == i + 1){
                char c = key[0];
                if ((c >= 65 && c <= 91) || (c >= 97 && c <= 122) || (c >= 48 && c <= 57))
                    e.key.keysym.sym = SDLKey(c);
                else
                    throw invalid_argument(c + " is not a recoqnized key.");
            }
            else if (specialKeys_.find(key) != specialKeys_.end()){
                 if (key == "space")
                      e.key.keysym.sym = SDLK_SPACE;
                 else if (key == "backspace")
                      e.key.keysym.sym = SDLK_BACKSPACE;
                 else if (key == "enter")
                      e.key.keysym.sym = SDLK_RETURN;
                 else if (key == "escape")
                      e.key.keysym.sym = SDLK_ESCAPE;
                 else if (key == "alt")
                      e.key.keysym.sym = SDLK_LALT;
                 else if (key == "alt gr")
                      e.key.keysym.sym = SDLK_RALT;
                 else if (key == "left shift")
                      e.key.keysym.sym = SDLK_LSHIFT;
                 else if (key == "right shift")
                      e.key.keysym.sym = SDLK_RSHIFT;
                 else if (key == "left ctrl")
                      e.key.keysym.sym = SDLK_LCTRL;
                 else if (key == "right ctrl")
                      e.key.keysym.sym = SDLK_RCTRL;
            }
            else {
                 throw invalid_argument(key + " is not a recoqnized key.");
            }
            
         }
         else{
             throw invalid_argument("Incorrect syntax for registering events");
         }
             
         registeredEvents_.insert(make_pair(e, function));
         
    }

	void GameEngine::run(){

		bool quit = false;
		int tickInterval = 1000 / fps_;
		Uint32 nextTick, lastTick;
		
		//deltaTime
        double dt = 0.03;

		while (!quit) {
			nextTick = SDL_GetTicks() + tickInterval;
			
			dt = SDL_GetTicks() - lastTick;
            
            SDL_Event eve;
        	while(SDL_PollEvent(&eve)){
                if (eve.type == SDL_QUIT){
                   quit = true;
                   break;
                }
                if (registeredEvents_.find(eve) != registeredEvents_.end())
                   (*registeredEvents_.find(eve)).second();
                

        	} // while pollevent
        	
        	//For each sprite that exists, every loop calls the update method
        	for(std::set<Sprite*>::iterator i = sprites_.begin(); i != sprites_.end(); ++i){
			    (*i)->update(sprites_, tickInterval/1000.0);  //The collection of sprites is sent along
            }
            
            lastTick = SDL_GetTicks();
            
			SDL_FillRect(mainScreen_, NULL, SDL_MapRGB(mainScreen_->format, 255,255,255));
			for(std::set<Sprite*>::const_iterator i = sprites_.begin(); i != sprites_.end(); ++i)
				(*i)->draw(mainScreen_);
			SDL_Flip(mainScreen_);

			int delay = nextTick - SDL_GetTicks();
			if (delay > 0)
				SDL_Delay(delay);
			
			//cout << dt << endl;
			
		} // while

	} // run

}//GameEng
